/**
 * xxxx
 *
 * @author:ivan.liu
 */
package com.wayz.service;

import com.wayz.constants.*;
import com.wayz.entity.dto.company.CompanyDto;
import com.wayz.entity.dto.company.CompanyPageDto;
import com.wayz.entity.pojo.company.*;
import com.wayz.entity.pojo.user.DUserSaas;
import com.wayz.entity.redis.company.RCompany;
import com.wayz.entity.redis.company.RDomainLogo;
import com.wayz.entity.redis.play.RPlayer;
import com.wayz.entity.redis.user.RUser;
import com.wayz.entity.vo.company.CompanyVo;
import com.wayz.exception.WayzException;
import com.wayz.mapper.DCompanyDAO;
import com.wayz.mapper.DTradeRecordDAO;
import com.wayz.redis.*;
import com.wayz.util.CollectionUtils;
import com.wayz.util.TimeHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 公司服务实现类
 *
 * @author yinjy
 *
 */
@Service(version = "1.0.0", protocol = "dubbo")
@RefreshScope
public class CompanySaasServiceImpl implements CompanySaasService {
    private static final String DB_NAME_PLAY = "db_saas_play";

    /** 公司DAO */
    @Resource(name = "dCompanyDAO")
    private DCompanyDAO dCompanyDAO = null;

    /** 公司对象 */
    @Resource(name = "rCompanyObject")
    private RCompanyObject rCompanyObject = null;

    /** 播控对象 */
    @Resource(name = "rPlayerObject")
    private RPlayerObject rPlayerObject = null;

    /** 域名logo对象 */
    @Resource(name = "rDomainLogoObject")
    private RDomainLogoObject rDomainLogoObject = null;

    /** 交易记录标识 */
    @Resource(name = "rTradeRecordId")
    private RTradeRecordId rTradeRecordId = null;

    /** 用户对象 */
    @Resource(name = "rUserObject")
    private RUserObject rUserObject;

    /** 公司标识 */
    @Resource(name = "redisUtils")
    private RedisUtils redisUtils;

    /** 版本 */
    @Autowired
    private VersionService versionService;

    /** 用户 */
    @Autowired
    private UserSaasService userSaasService = null;

    /** 代理商 */
    @Autowired
    private AgentService agentService;

    /** 部门服务 */
    @Resource(name = "departmentService")
    private DepartmentService departmentService = null;

    /** 交易记录DAO */
    @Resource(name = "dTradeRecordDAO")
    private DTradeRecordDAO dTradeRecordDAO = null;

    /**
     * 查询公司视图
     *
     * @return
     */
    @Override
    public List<ViewMap> queryViewMap() {
        return dCompanyDAO.findViewMap();
    }

    /** 媒体位标识播控器编码值 */
    @Resource(name = "rPositionIdPlayerCodeValue")
    private RPositionIdPlayerCodeValue rPositionIdPlayerCodeValue = null;

    /**
     * 获取公司详情
     *
     * @param myId 我的标识
     * @param id 公司标识
     * @return 公司详情
     * @throws WayzException
     */
    @Override
    public CompanyVo getCompanyDetail(Long myId, Long id) throws WayzException {
        // 获取数据
        DCompanyExt companyExt = dCompanyDAO.getCompanyExtById(id);
        // 初始化
        CompanyVo companyVo = new CompanyVo();
        RCompany rCompany = rCompanyObject.get(id);
        if (rCompany == null) {
            throw new WayzException("无公司缓存信息,请联系管理员!");
        }
        if (rCompany.getIsAdPaln() == null || false == rCompany.getIsAdPaln().booleanValue()) {
            companyVo.setIsAdPlan(false);
        }
        else {
            companyVo.setIsAdPlan(true);
        }
        // 数据赋值
        BeanUtils.copyProperties(companyExt, companyVo);
        companyVo.setStatusName(CCompanyStatus.getDescription(companyExt.getStatus()));
        companyVo.setValidUntilDate(companyExt.getValidUntilDate());
        companyVo.setAlreadyMaterialLimit(rCompany.getMaterialLimit() - rCompany.getSurplusMaterialLimit());
        companyVo.setSurplusMaterialLimit(rCompany.getSurplusMaterialLimit());
        // 返回数据
        return companyVo;
    }

    /**
     * 创建公司
     *
     * @throws WayzException 平台异常
     */
    @Override
    public Long createCompany(Long myId, CompanyDto companyDto) throws WayzException {
        // 获取公司编号
        Long companyId = redisUtils.incrBy(BeanIdKeyEnum.COMPANY_SAAS.getKey(), RedisUtils.STEP_SIZE);
        // 初始化用户管理员账号
        Long userId = this.initUser(myId, companyId, companyDto);
        // 初始化用户播控截屏日志表
        dCompanyDAO.createUserPlaySnapshot(DB_NAME_PLAY, companyId);
        // 写入mysql数据
        DCompanyExt dCompanyExt = this.insertCompany(myId, companyId, companyDto, userId);

        // 代理商处理
        if (companyDto.getAgentId() != null) {
            agentService.createAgentRelation(companyId, companyDto.getAgentId(), companyDto.getIsLogin());
        }
        // 写入缓存数据
        RCompany rRcompany = new RCompany();
        BeanUtils.copyProperties(dCompanyExt, rRcompany);
        rRcompany.setCompanyId(dCompanyExt.getId());
        rRcompany.setSurplusUserLimit(dCompanyExt.getUserLimit());
        rRcompany.setSurplusMaterialLimit(dCompanyExt.getMaterialLimit());
        rRcompany.setBalance(0.0);
        if (dCompanyExt.getValidUntilDate() != null) {
            rRcompany.setValidUntilDate(TimeHelper.getDate(dCompanyExt.getValidUntilDate()));
        }

        rCompanyObject.set(dCompanyExt.getId(), rRcompany);
        // 创建总部
        departmentService.createDepartment(myId, companyId, "总部", -1L);

        // 返回数据
        return companyId;
    }

    /**
     * 公司存入mysql数据库
     *
     */
    private DCompanyExt insertCompany(Long myId, Long companyId, CompanyDto companyDto, Long userId)
            throws WayzException {
        // 公司名称是否存在
        DCompany dCompany = dCompanyDAO.getByName(companyDto.getName());
        if (dCompany != null) {
            throw new WayzException("公司名称已存在!");
        }
        // 创建
        DCompanyExt dCompanyExt = new DCompanyExt();
        BeanUtils.copyProperties(companyDto, dCompanyExt);
        dCompanyExt.setId(companyId);
        dCompanyExt.setUserId(userId);
        dCompanyExt.setRequireDataAuth(false);
        dCompanyExt.setAccessDsp(false);
        dCompanyExt.setPlanLimit(0);
        dCompanyExt.setMaterialLimit(companyDto.getMaterialSize().longValue() * 1024 * 1024);
        dCompanyExt.setStatus(companyDto.getStatus());
        if (StringUtils.isNotEmpty(companyDto.getValidUntilDate())) {
            dCompanyExt.setValidUntilDate(TimeHelper.getDate(companyDto.getValidUntilDate()));
        }
        dCompanyExt.setIsWatermark(companyDto.getIsWatermark());
        dCompanyExt.setIsDeleted(false);
        dCompanyExt.setCreatorId(myId);
        dCompanyDAO.create(dCompanyExt);
        return dCompanyExt;
    }

    /**
     * 初始化saas管理员用户账号
     *
     * @param myId
     * @param companyDto
     * @param companyId
     * @return
     * @throws WayzException
     */
    private Long initUser(Long myId, Long companyId, @org.jetbrains.annotations.NotNull CompanyDto companyDto) throws WayzException {
        Long roleId = versionService.getRoleIdByVersionId(myId, companyDto.getVersionId());
        return userSaasService.createUser(myId, companyId, roleId, companyDto.getUserName(),
                companyDto.getContacts(), companyDto.getTelephone(), companyDto.getEmail());
    }

    @Override
    public Integer countCompanyByVersionId(Long versionId) {
        return dCompanyDAO.countCompanyByVersionId(versionId);
    }

    /**
     * 修改公司
     *
     * @param myId 我的标识
     * @return platform应答
     * @throws WayzException 平台异常
     */
    @Override
    public void modifyCompany(Long myId, CompanyDto companyDto) throws WayzException {
        // 校验参数
        RCompany rCompany = this.checkParam(companyDto);

        // 更新mysql数据库
        this.updateCompany(companyDto);
        if (companyDto.getAgentId() == null) {
            agentService.deleteAgentRelation(rCompany.getCompanyId());
        }
        else {
            agentService.updateAgentRelation(rCompany.getCompanyId(), companyDto.getAgentId(),
                    companyDto.getIsLogin());
        }

        // 更新缓存中公司信息
        rCompanyObject.set(rCompany.getCompanyId(), rCompany);
    }

    /**
     * 更新数据库公司信息
     *
     * @param companyDto
     * @return
     */
    private void updateCompany(CompanyDto companyDto) throws WayzException {
        // 修改公司
        DCompanyExt dCompanyExt = new DCompanyExt();
        BeanUtils.copyProperties(companyDto, dCompanyExt);
        dCompanyExt.setStatus(companyDto.getStatus());
        if (StringUtils.isNotEmpty(companyDto.getValidUntilDate())) {
            dCompanyExt.setValidUntilDate(TimeHelper.getDate(companyDto.getValidUntilDate()));
        }
        Long fileSize = Long.valueOf(companyDto.getMaterialSize().longValue() * 1024 * 1024);
        dCompanyExt.setMaterialLimit(fileSize);
        dCompanyDAO.modify(dCompanyExt);

        // fixme 版本变更逻辑后期完善 如果版本变更了 修改公司主账户角色
        // Integer versionId = rCompany.getVersionId();
        // Long versionIdModify = companyCreateVo.getVersionId();
        // if (versionId - versionIdModify != 0) {
        // Long roleId = versionService.getVersionRoleIdById(myId,
        // companyCreateVo.getVersionId());
        // userSaasService.updateUserSaasRoleId(rCompany.getUserId(), roleId);
        // }
    }

    /**
     * 校验参数并维护缓存
     *
     */
    private RCompany checkParam(CompanyDto companyDto) throws WayzException {
        Long id = companyDto.getId();
        RCompany rCompany = rCompanyObject.get(companyDto.getId());
        rCompany.setCompanyId(id);
        // 如果公司名称变化
        String name = companyDto.getName();
        if (!rCompany.getName().equals(name)) {
            DCompany dCompany1 = dCompanyDAO.getByName(name);
            if (dCompany1 != null && !dCompany1.getId().equals(id)) {
                throw new WayzException("公司名称已存在");
            }
            rCompany.setName(name);
        }

        // 如果修改了版本
        if (!rCompany.getVersionId().equals(companyDto.getVersionId())) {
            // 获取版本信息
            // RFunctionVersion rFunctionVersion =
            // redisUtils.hGetAllAsBean(RFunctionVersion.getKey(companyCreateVo.getVersionId()),
            // RFunctionVersion.class);
            Long roleId = versionService.getRoleIdByVersionId(null, companyDto.getVersionId());
            CompanyVo companyMainAccount = userSaasService.getCompanyMainAccount(companyDto.getId(),
                    CUserType.MAIN_ACCOUNT.getValue());
            userSaasService.updateUserSaasRoleId(companyMainAccount.getId(), roleId);
        }

        // 如果修改了手机号
        String telephone = companyDto.getTelephone();
        if (!rCompany.getTelephone().equals(telephone)) {
            DUserSaas dUserSaas = userSaasService.getUserSaasByPhone(telephone);
            if (dUserSaas != null && !dUserSaas.getId().equals(rCompany.getUserId())) {
                throw new WayzException("手机号已存在");
            }
            rCompany.setTelephone(telephone);
            // 修改相应用户的手机号
            userSaasService.modifyUserPhone(rCompany.getUserId(), telephone);
        }

        // 如果修改了联系人 修改主账户的name
        String contacts = companyDto.getContacts();
        if (!rCompany.getContacts().equals(contacts)) {
            userSaasService.modifyUserName(rCompany.getUserId(), contacts);
            rCompany.setContacts(contacts);
        }

        // 如果修改用户数量
        Integer userLimitModify = companyDto.getUserLimit();
        Integer userLimit = rCompany.getUserLimit();
        if (!userLimit.equals(userLimitModify)) {
            Integer surplusUserLimit = rCompany.getSurplusUserLimit();
            // 计算实际使用量
            int usageUser = userLimit - surplusUserLimit;
            // 修改后的剩余量
            int usageUserModify = userLimitModify - usageUser;
            if (usageUserModify < 0) {
                throw new WayzException("用户数量小于当前使用量，无法修改");
            }
            rCompany.setUserLimit(userLimitModify);
            rCompany.setSurplusUserLimit(usageUserModify);
        }

        rCompany.setEmail(companyDto.getEmail());
        rCompany.setVersionId(companyDto.getVersionId());
        rCompany.setIsAdPaln(companyDto.getIsAdPaln());
        rCompany.setAgentId(companyDto.getAgentId());
        rCompany.setIsLogin(companyDto.getIsLogin());
        rCompany.setStatus(companyDto.getStatus());
        rCompany.setValidUntilDate(companyDto.getValidUntilDate());

        // 如果修改了素材空间大小
        Long materialLimitOld = rCompany.getMaterialLimit();
        Long surplusMaterialLimit = rCompany.getSurplusMaterialLimit();
        // 使用的
        Long consumMaterialLimit = materialLimitOld - surplusMaterialLimit;
        Long materialLimit = companyDto.getMaterialSize().longValue() * 1024 * 1024;

        if (consumMaterialLimit > materialLimit) {
            throw new WayzException("素材空间小于当前使用量，无法修改");
        }
        rCompany.setMaterialLimit(materialLimit);
        rCompany.setSurplusMaterialLimit(materialLimit - consumMaterialLimit);

        return rCompany;
    }

    /**
     * 改变公司状态 (1:启用 0:禁用;)
     *
     * @param companyId
     * @param status
     * @return
     */
    @Override
    public Integer modifyCompanyStatus(Long companyId, Short status, String validUntilDate, Boolean isWatermark) {
        Integer count = dCompanyDAO.updateCompanyStatus(companyId, status, validUntilDate, isWatermark);
        RCompany rCompany = new RCompany();
        rCompany.setStatus(status);
        rCompany.setValidUntilDate(validUntilDate);
        rCompany.setIsWatermark(isWatermark);
        rCompanyObject.set(companyId, rCompany);

        // 测试账号中设备有效期 TODO
        if (status == CCompanyStatus.TESTING.getValue()) {
            dCompanyDAO.updatePositionUntilDate(companyId, validUntilDate);

            // 维护播控状态
            // 获取账户下媒体位
            List<Long> positionIdList = dCompanyDAO.queryPositionIdByCompany(companyId);
            if (CollectionUtils.isNotEmpty(positionIdList)) {
                for (Long id : positionIdList) {
                    String code = rPositionIdPlayerCodeValue.get(id);
                    if (StringUtils.isEmpty(code)) {
                        continue;
                    }
                    rPlayerObject.setShort(code, RPlayer.STATUS, CPositionStatus.NORMAL.getValue());
                }
            }
        }
        return count;
    }

    /**
     * 查询公司列表
     *
     * @param companyPageDto 分页参数
     * @return
     */
    @Override
    public PageVo<CompanyVo> queryCompany(Long myId, CompanyPageDto companyPageDto) {
        PageVo<CompanyVo> companyVoPage = new PageVo<>();
        Integer count = dCompanyDAO.countByCondition(companyPageDto.getStatus(), companyPageDto.getSourceType(), companyPageDto.getName(), companyPageDto.getVersionId(), companyPageDto.getPhone(), companyPageDto.getAgentId());
        if (count <= 0) {
            return companyVoPage;
        }
        List<DCompany> dCompanies = dCompanyDAO.queryExtByCondition(companyPageDto.getStatus(), companyPageDto.getSourceType(), companyPageDto.getName(), companyPageDto.getVersionId(), companyPageDto.getPhone(), companyPageDto.getAgentId(), companyPageDto.getStartIndex(), companyPageDto.getPageSize());

        List<CompanyVo> companyList = new ArrayList<CompanyVo>();
        CompanyVo companyVo;
        for (DCompany dCompany : dCompanies) {
            companyVo = new CompanyVo();
            BeanUtils.copyProperties(dCompany, companyVo);
            companyVo.setValidUntilDate(dCompany.getValidUntilDate());
            companyVo.setStatusName(CCompanyStatus.getDescription(dCompany.getStatus()));
            companyVo.setCreatedTime(dCompany.getCreatedTime());
            companyList.add(companyVo);
        }
        companyVoPage.setList(companyList);
        companyVoPage.setTotalCount(count);
        return companyVoPage;
    }

    /**
     * OEM配置
     *
     * @param myId
     * @param logo
     * @param domain
     * @param websiteTitle
     */
    @Override
    public void updateCompanyOEM(Long myId, Long id, String logo, String domain, String websiteTitle) {
        dCompanyDAO.insertCompanyOEM(id, logo, domain, websiteTitle);
        String oldDomain = rCompanyObject.getString(id, RCompany.DOMAIN);
        RCompany rCompany = new RCompany();
        rCompany.setLogo(logo);
        rCompany.setDomain(domain);
        rCompany.setWebsiteTitle(websiteTitle);
        rCompanyObject.set(id, rCompany);

        // 设置redis
        if (StringUtils.isNotEmpty(oldDomain) && !domain.equals(oldDomain)) {
            rDomainLogoObject.remove(oldDomain);
        }
        RDomainLogo rDomainLogo = new RDomainLogo();
        rDomainLogo.setDomainName(domain);
        rDomainLogo.setLogo(logo);
        rDomainLogo.setWebsiteTitle(websiteTitle);
        rDomainLogoObject.set(domain, rDomainLogo);
    }

    /**
     * 获取公司OEM信息
     *
     * @param myId
     * @param id
     * @return
     */
    @Override
    public DCompanyOEM getCompanyOEM(Long myId, Long id) {
        DCompany dCompany = dCompanyDAO.get(id);
        DCompanyOEM DCompanyOEM = new DCompanyOEM();
        BeanUtils.copyProperties(dCompany, DCompanyOEM);
        return DCompanyOEM;
    }

    /**
     * 逻辑删除公司
     *
     * @param myId
     * @param id
     */
    @Override
    public void deleteCompany(Long myId, Long id) {
        dCompanyDAO.deleteCompanyById(id);
        rCompanyObject.remove(id);
    }

    /**
     * 公司充值
     *
     * @param myId 用户标识
     * @param companyId 公司标识
     * @param amount 充值金额(元)
     * @param payment 实付金额(元)
     * @param tradeType 充值类型(11:现金充值 12:红包充值 13:转账充值 14:退款充值)
     * @param remark 备注
     *
     * @return 账户余额
     * @throws WayzException 平台异常
     */
    @Override
    public Double rechargeCompany(Long myId, Long companyId, Double amount, Double payment, Short tradeType, String remark)
            throws WayzException {
        // 初始化
        Double balance = rCompanyObject.getDouble(companyId, RCompany.BALANCE);
        if (balance == null) {
            balance = 0.0;
        }
        // 修改余额
        balance = balance + amount;
        rCompanyObject.setDouble(companyId, RCompany.BALANCE, balance);
        DCompanyExt modify = new DCompanyExt();
        modify.setId(companyId);
        modify.setBalance(balance);
        dCompanyDAO.modify(modify);

        // 充值成功：记录交易记录
        DTradeRecordExt dTradeRecordCreate = new DTradeRecordExt();

        dTradeRecordCreate.setAmount(amount);
        dTradeRecordCreate.setPayment(payment);
        dTradeRecordCreate.setCompanyId(companyId);
        dTradeRecordCreate.setOperatorId(myId);
        dTradeRecordCreate.setOperatorType(COperatorType.ADMIN.getValue());
        dTradeRecordCreate.setTradeType(tradeType);
        dTradeRecordCreate.setRemark(remark);
        dTradeRecordCreate.setBalance(balance);
        dTradeRecordDAO.create(rTradeRecordId.increment(), dTradeRecordCreate);

        // 返回数据
        return balance;
    }

    /**
     * 查询交易概要
     *
     * @param myId 我的客户标识
     * @param companyId 公司标识
     * @param operatorType 操作员类型类型(1:平台 2:代理 3:租户 )
     * @param tradeType 交易类型(11:现金充值 12:红包充值 13:转账充值 14:退款充值 21:设备续期消费
     *            22:空间扩展消费)
     * @param beginDate 开始日期(YYYY-MM-DD)
     * @param endDate 结束日期(YYYY-MM-DD)
     * @param startIndex 开始序号
     * @param pageSize 页面大小
     * @return 交易概要分页
     */
    @Override
    public PageVo<TradeRecord> queryTradeRecord(Long myId, Long companyId, Short operatorType, Short tradeType,
                                              String beginDate, String endDate, Integer startIndex, Integer pageSize) throws WayzException {
        // 初始化
        PageVo<TradeRecord> recordPage = new PageVo<TradeRecord>();
        List<TradeRecord> recordList = new ArrayList<TradeRecord>();
        Integer totalCount = 0;

        // 统计数据
        totalCount = dTradeRecordDAO.count(companyId, operatorType, tradeType, beginDate, endDate);
        // 查询数据
        List<DTradeRecord> dRecordList = dTradeRecordDAO.query(companyId, operatorType, tradeType, beginDate, endDate,
                startIndex, pageSize);
        if (CollectionUtils.isNotEmpty(dRecordList)) {
            for (DTradeRecord dRecord : dRecordList) {
                TradeRecord record = new TradeRecord();
                record.setId(dRecord.getId());
                record.setAmount(dRecord.getAmount());
                record.setPayment(dRecord.getPayment());
                record.setBalance(dRecord.getBalance());
                record.setOperatorType(dRecord.getOperatorType());
                String operatorName = COperatorType.getDescription(dRecord.getOperatorType());
                if (dRecord.getOperatorType().equals(COperatorType.TENANT.getValue())) {
                    operatorName = rUserObject.getString(dRecord.getOperatorId(), RUser.NAME);
                }
                record.setOperatorName(operatorName);
                record.setRemark(dRecord.getRemark());
                record.setTradeType(dRecord.getTradeType());
                record.setTradeTypeName(CTradeType.getDescription(dRecord.getTradeType()));
                record.setCreatedTime(TimeHelper.getTimestamp(dRecord.getCreatedTime()));
                recordList.add(record);
            }
        }
        // 赋值
        recordPage.setList(recordList);
        recordPage.setTotalCount(totalCount);

        // 返回数据
        return recordPage;
    }

    /**
     * 获取公司主账户
     *
     * @param myId 我的标识
     * @param id 公司标识
     * @return 云歌应答
     */
    @Override
    public CompanyVo getCompanyMainAccount(Long myId, Long id) throws WayzException {
        return userSaasService.getCompanyMainAccount(id, CUserType.MAIN_ACCOUNT.getValue());
    }

    /**
     * 重置主账号密码
     *
     * @param myId
     * @param id
     * @return
     */
    @Override
    public void resetUserPassword(Long myId, Long id, String newPassword) throws WayzException {
        userSaasService.resetUserPassword(id, CUserType.MAIN_ACCOUNT.getValue(), newPassword);
    }
}
